/*
 *   This file is part of ed_pvr.
 *
 *   ed_pvr is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   ed_pvr is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with ed_pvr.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <fcntl.h>
#include <unistd.h>
#include <memory.h>
#include <getopt.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <netdb.h>

#include "protocol.h"
#include "utils.h"
#include "timers.h"
#include "device.h"


size_t _protocol_send_cmd(int, PROTOCOL_CMD_STRUCT *);
int _protocol_do_connect(char *, uint16_t, int timeout);

size_t _protocol_send_8(int, uint8_t);
size_t _protocol_send_16(int, uint16_t);
size_t _protocol_send_32(int, uint32_t);
size_t _protocol_send_64(int, uint64_t);

size_t _protocol_get_8(int, uint8_t*);
size_t _protocol_get_16(int, uint16_t*);
size_t _protocol_get_32(int, uint32_t*);
size_t _protocol_get_64(int, uint64_t*);

// --------------------------

// ---------- SENDs
size_t _protocol_send_64(int handle, uint64_t p)
{
//	printf("[PROTO] SEND64: %" PRId64" -- 0x%lx\n", p, p);
	if (handle)
		return write(handle, &p, sizeof(uint64_t));
	return -1;
}

size_t _protocol_send_32(int handle, uint32_t p)
{
	if (handle)
		return write(handle, &p, sizeof(uint32_t));
	return -1;
}

size_t _protocol_send_16(int handle, uint16_t p)
{
	if (handle)
		return write(handle, &p, sizeof(uint16_t));
	return -1;
}

size_t _protocol_send_8(int handle, uint8_t p)
{
	if (handle)
		return write(handle, &p, sizeof(uint8_t));
	return -1;
}

//  ------------ GETSs
size_t _protocol_get_64(int handle, uint64_t *p)
{
	if (handle)
		return get_bytes_from_socket(handle, (uint8_t *)&p, sizeof(uint64_t), 2000, NULL);
	return -1;
}
size_t _protocol_get_32(int handle, uint32_t *p)
{
	if (handle)
		return get_bytes_from_socket(handle, (uint8_t *)&p, sizeof(uint32_t), 2000, NULL);
	return -1;
}

size_t _protocol_get_16(int handle, uint16_t *p)
{
	if (handle)
		return get_bytes_from_socket(handle, (uint8_t *)&p, sizeof(uint16_t), 2000, NULL);
	return -1;
}

size_t _protocol_get_8(int handle, uint8_t *p)
{
	if (handle)
		return get_bytes_from_socket(handle, (uint8_t *)&p, sizeof(uint8_t), 2000, NULL);
	return -1;
}


// -----------------------------=
size_t protocol_send_tuner_pos(int handle, uint64_t pos)
{
//	printf("protocol_send_tuner_pos: %" PRId64" -- 0x%lx\n", pos, pos);
	if (handle)
		return _protocol_send_64(handle, pos);
	return -1;
}

size_t protocol_send_tuner_init_status(int handle, uint8_t stat)
{
	if (handle && stat)
		return _protocol_send_8(handle, stat);
	return -1;
}

size_t protocol_send_tuner_id(int handle, uint8_t id)
{
	if (handle && id)
		return _protocol_send_8(handle, id);
	return -1;
}


int protocol_alive(char *ip, uint16_t port, int timeout)
{
	int handle = _protocol_do_connect(ip, port, timeout);
	if (handle)
	{
		int err = 0;
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = PROTO_INIT_CONNECTION;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		if (_protocol_send_cmd(handle, &pstruct) == 1)
		{
			uint8_t resp = 0;
			int sz = get_bytes_from_socket(handle, &resp, sizeof(resp), 5000, &err);
			close(handle);

			if (sz == sizeof(resp) && resp == PROTOCOL_INIT_GOOD)
			{
				return 1;
			}

			return 0;
		}
	}
	return -1;
}
int _protocol_do_connect(char *ip, uint16_t port, int timeout)
{
	int sock = 0, err = 0, sz = 0;
	char req[1024] = {0};
	uint8_t moo=0xFF;

	//printf("_protocol_do_connect start\n");
	sock = doconnect(ip, port, 0);

	if (sock ==  -1)
	{
		printf("NOOOOO\n");
		return 0;
	}
	sprintf(req, "eTUNER V001 \n\n");
	sz = write_bytes_to_socket(sock, (uint8_t*)req, strlen(req), 2000, NULL);

	if (sz ==  -1)
	{
		printf("[CeTUNE] Error sending GET req\n");
		close(sock);
		return 0;
	}

	memset(&req, 0, 1024);
//	sz = get_bytes_from_socket(sock, &moo, 1, 5, 0, 0);
	sz = get_bytes_from_socket(sock, &moo, 1, 2000, &err);

	if (sz == -1)
	{
		close(sock);
		return 0;
	}

	if (moo == PROTOCOL_INIT_GOOD)
		return sock;

	return 0;
}

size_t protocol_get_timer_seqnum(char *ip, uint16_t port, int * h1)
{
	int handle = _protocol_do_connect(ip, port, 0);

	if (handle && h1)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		memcpy(h1, &handle, sizeof(int));
		pstruct.cmd = PROTO_GET_TIMER_SEQNUM;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_get_req_seqnum(char *ip, uint16_t port, int * h1)
{
	int handle = _protocol_do_connect(ip, port, 0);

	if (handle && h1)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		memcpy(h1, &handle, sizeof(int));
		pstruct.cmd = PROTO_GET_REC_SEQNUM;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}


size_t protocol_get_tuner_count(char *ip, uint16_t port, int * h1)
{
	int handle = _protocol_do_connect(ip, port, 0);

	if (handle && h1)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		memcpy(h1, &handle, sizeof(int));
		pstruct.cmd = PROTO_QUERY_TUNER_COUNT;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}


//size_t protocol_get_channel_epg(char *ip, uint16_t port, int *h1, char *id)
size_t protocol_get_channel_epg(char *ip, uint16_t port, int *h1, TIMER_STRUCT_SEND *timer)
{
	int handle = _protocol_do_connect(ip, port, 0);
	if (handle && h1)
	{
//		TIMER_STRUCT_SEND timer = {0};

		PROTOCOL_CMD_STRUCT pstruct = {0};
		memcpy(h1, &handle, sizeof(int));
		pstruct.cmd = PROTO_GET_CHAN_EPG;

		pstruct.dataptr = (uint8_t *)timer;
		pstruct.dataptr_size = sizeof(*timer);
/*
		pstruct.dataptr = (uint8_t*)id;
		pstruct.dataptr_size = strlen(id) + 1;
*/
		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}


size_t protocol_epg_reload(char *ip, uint16_t port, int *h1, char *newfile)
{
	int handle = _protocol_do_connect(ip, port, 0);
	if (handle && h1)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		char *tmp = PROTOCOL_RELOAD_CURRENT_STR;
		if (newfile)
			tmp = newfile;

		memcpy(h1, &handle, sizeof(int));
		pstruct.cmd = PROTO_RELOAD_EPG_FILE;
		pstruct.dataptr = (uint8_t*)tmp;
		pstruct.dataptr_size = strlen(tmp) + 1;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_get_channel_count(char *ip, uint16_t port, int *h1)
{
	int handle = _protocol_do_connect(ip, port, 0);
	if (handle && h1)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		memcpy(h1, &handle, sizeof(int));
		pstruct.cmd = PROTO_QUERY_CHANNEL_COUNT;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_get_rec_count(char *ip, uint16_t port, int *h1)
{
	int handle = _protocol_do_connect(ip, port, 0);
	if (handle && h1)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		memcpy(h1, &handle, sizeof(int));
		pstruct.cmd = PROTO_QUERY_REC_COUNT;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_get_timer_count(char *ip, uint16_t port, int *h1)
{
	int handle = _protocol_do_connect(ip, port, 0);
	if (handle && h1)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		memcpy(h1, &handle, sizeof(int));
		pstruct.cmd = PROTO_QUERY_TIMER_COUNT;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_get_stream_info(char *ip, uint16_t port, int *h1)
{
	int handle = _protocol_do_connect(ip, port, 0);
	if (handle && h1)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		memcpy(h1, &handle, sizeof(int));

		pstruct.cmd = PROTO_QUERY_STREAM_INFO;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_get_stream_info2(int handle)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = PROTO_QUERY_STREAM_INFO;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_get_channel_list(char *ip, uint16_t port, int *h1)
{
	int handle = _protocol_do_connect(ip, port, 0);
	if (handle && h1)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		memcpy(h1, &handle, sizeof(int));

		pstruct.cmd = PROTO_QUERY_CHANNEL_LIST;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_get_rec_list(char *ip, uint16_t port, int *h1)
{
	int handle = _protocol_do_connect(ip, port, 0);
	if (handle && h1)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		memcpy(h1, &handle, sizeof(int));

		pstruct.cmd = PROTO_QUERY_REC_LIST;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

uint64_t protocol_get_tuner_time_pos(int handle)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_GET_STREAM_POS;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_get_tuner_id(int handle)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_GET_STREAM_ID;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

uint64_t protocol_get_tuner_time_endpos(int handle)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_GET_STREAM_END_POS;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}
/*
uint64_t protocol_get_tuner_time_startpos(int handle)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_GET_STREAM_START_POS;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}
*/
uint64_t protocol_get_tuner_time_startpos2(int handle)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_GET_STREAM_START_POS2;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}


uint64_t protocol_get_tuner_size_endpos(int handle)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_GET_STREAM_SZ_END_POS;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

uint64_t protocol_get_tuner_size_startpos(int handle)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_GET_STREAM_SZ_START_POS;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return 0;
}

size_t protocol_get_tuner_size_pos(int handle)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_GET_STREAM_SZ_POS;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_set_tuner_size_pos(int handle, uint64_t pos)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_SET_STREAM_SZ_POS;
		pstruct.dataptr_size = sizeof(pos);
		pstruct.dataptr = (uint8_t*)&pos;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}


//-----------------------------------------

size_t protocol_get_timer_list(char *ip, uint16_t port, int *h1)
{
	int handle = _protocol_do_connect(ip, port, 0);
	if (handle && h1)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		memcpy(h1, &handle, sizeof(int));

		pstruct.cmd = PROTO_QUERY_TIMER_LIST;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

/*
size_t protocol_get_timer_list(int handle)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_QUERY_TIMER_LIST;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}
*/
size_t protocol_add_timer(char *ip, uint16_t port, uint8_t *data, uint32_t data_sz, int *h1)
{
	int handle = _protocol_do_connect(ip, port, 0);

	if (handle && h1 && data && data_sz)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		memcpy(h1, &handle, sizeof(int));

		pstruct.cmd = PROTO_TIMER_ADD;
//		printf("hh: %d\n", data_sz);
		pstruct.dataptr_size = data_sz;
		pstruct.dataptr = data;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}


size_t protocol_del_timer(int handle, uint32_t id)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_TIMER_DEL;
		pstruct.dataptr = (uint8_t*)&id;
		pstruct.dataptr_size = sizeof(id);
		printf("MMM: %d -- %d\n", pstruct.dataptr_size, *((uint32_t*)pstruct.dataptr));
		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_del_timer2(char *ip, uint16_t port, uint32_t id, int *h1)
{

	int handle = _protocol_do_connect(ip, port, 0);

	if (handle && h1)
	{
		memcpy(h1, &handle, sizeof(int));
		return protocol_del_timer(handle, id);
	}
	return 0;
}

/*
size_t protocol_stop_timer(int handle, uint32_t id)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_TIMER_STOP;
		pstruct.dataptr_size = sizeof(id);
		pstruct.dataptr = (uint8_t*)&id;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}
*/

/*
size_t protocol_set_tuner_channel(int handle, uint32_t channel)
{
	if (handle && channel)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_TUNE_AND_STREAM;
		pstruct.dataptr_size = sizeof(channel);
		pstruct.dataptr = (uint8_t*)&channel;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}
*/

size_t protocol_set_tuner_channel(int handle, PROTOCOL_TUNE_STRUCT *tchan)
{
	if (handle && tchan)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_TUNE_AND_STREAM;
		pstruct.dataptr_size = sizeof(PROTOCOL_TUNE_STRUCT);
		pstruct.dataptr = (uint8_t*)&tchan;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_send_keepalive(int handle)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd =  PROTO_KEEP_ALIVE;
		pstruct.dataptr_size = 0;
		pstruct.dataptr = NULL;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_set_tuner_time_pos(int handle, uint64_t pos)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_SET_STREAM_POS;
		pstruct.dataptr_size = sizeof(pos);
		pstruct.dataptr = (uint8_t*)&pos;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}
/*
size_t protocol_play_rec_id2(char *ip, uint16_t port, int * h1, uint32_t id)
{
	int handle = _protocol_do_connect(ip, port, 0);

	if (handle && h1)
	{
		memcpy(h1, &handle, sizeof(int));
		return protocol_play_rec_id(handle, id);
	}
	return -1;
}
*/
size_t protocol_play_rec_id(int handle, uint32_t id)
{
	if (handle && id)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_REC_PLAY;
		pstruct.dataptr_size = sizeof(id);
		pstruct.dataptr = (uint8_t*)&id;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_del_rec_id(int handle, uint32_t id)
{
	if (handle)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_REC_DEL;
		pstruct.dataptr_size = sizeof(id);
		pstruct.dataptr = (uint8_t*)&id;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}

size_t protocol_del_rec_id2(char *ip, uint16_t port, uint32_t id, int *h1)
{

	int handle = _protocol_do_connect(ip, port, 0);

	if (handle && h1)
	{
/*
		PROTOCOL_CMD_STRUCT pstruct = {0};
		memcpy(h1, &handle, sizeof(int));

		pstruct.cmd = PROTO_REC_DEL;
//		printf("hh: %d\n", data_sz);
		pstruct.dataptr_size = sizeof(id);
		pstruct.dataptr = (uint8_t*)&id;

		return _protocol_send_cmd(handle, &pstruct);
*/
		memcpy(h1, &handle, sizeof(int));
		return protocol_del_rec_id(handle, id);
	}
	return 0;
}
/*
size_t protocol_stop_rec_id(int handle, uint32_t id)
{
	if (handle && id)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};

		pstruct.cmd = PROTO_REC_STOP;
		pstruct.dataptr_size = sizeof(id);
		pstruct.dataptr = (uint8_t*)&id;

		return _protocol_send_cmd(handle, &pstruct);
	}
	return -1;
}
*/
void protocol_free_cmd_struct(PROTOCOL_CMD_STRUCT * p)
{
	if (p)
	{
		if (p->dataptr)
			free(p->dataptr);
		free(p);
	}
}


PROTOCOL_CMD_STRUCT *protocol_get_cmd(int handle)
{
	PROTOCOL_CMD_STRUCT *ret = calloc(1, sizeof(PROTOCOL_CMD_STRUCT));
	if (handle)
	{
		int err = 0;
		uint32_t _input = 0;
//		size_t _rc = 0;
//		printf("protocol_get_cmd 1\n");
		while(ret->rc == 0)
		{
//		printf("protocol_get_cmd 2\n");
			ret->rc = get_bytes_from_socket(handle, (uint8_t*)&_input, sizeof(uint32_t), 2000, &err);
//			ret->rc = get_bytes_from_socket(handle, (uint8_t*)&_input, sizeof(uint32_t), 0, &err);
			if (ret->rc <= 0)
			{
//				printf("protocol_get_cmd 1: %d (%s)\n",errno, strerror(errno));
				return ret;
			}
/*
			else if (ret->rc == 0)
			{
				usleep(1000*250);
			}
*/
//		printf("protocol_get_cmd 3\n");

		}

		if (!((_input & PROTO_CMD_MASK) == PROTO_CMD_START))
		{
//			printf("protocol_get_cmd 2\n");
			ret->rc = -5;
			return ret;
		}

//		if (!ret)
//			ret = calloc(1, sizeof(PROTOCOL_CMD_STRUCT));

		ret->cmd  = _input & 0x000000FF;
//		_cmd = _input & 0x000000FF;
//		printf("CMD: 0x%x\n", ret->cmd);

		switch(ret->cmd)
		{
			case PROTO_GET_CHAN_EPG:
			case PROTO_TIMER_DEL:
			case PROTO_TIMER_ADD:
			case PROTO_SET_STREAM_POS:
			case PROTO_SET_STREAM_SZ_POS:
			case PROTO_TUNE_AND_STREAM:
			case PROTO_REC_PLAY:
			case PROTO_REC_DEL:
			case PROTO_RELOAD_EPG_FILE:
			{
				uint32_t data_sz = 0;
				ret->rc = get_bytes_from_socket(handle, (uint8_t*)&data_sz, sizeof(data_sz), 3000, &err);
//				ret->rc = get_bytes_from_socket(handle, (uint8_t*)&data_sz, sizeof(data_sz), 0, &err);

				if (ret->rc > 0)
				{
					ret->dataptr_size = data_sz;
					ret->dataptr = calloc(1, ret->dataptr_size);
					ret->rc = get_bytes_from_socket(handle, ret->dataptr, ret->dataptr_size, 3000, &err);
//					ret->rc = get_bytes_from_socket(handle, ret->dataptr, ret->dataptr_size, 0, &err);
				}
				else
				{
					printf("[PROTO] !!!! protocol_get_cmd error: %d (%s)\n", ret->rc, strerror(errno));
				}
			}
			break;

//			break;
/*
			case PROTO_TIMER_LIST:
			case PROTO_GET_STREAM_END_POS:
			case PROTO_GET_STREAM_POS:
			case PROTO_GET_STREAM_ID:
*/
			default:
			break;
		}
	}
	return ret;
}


size_t _protocol_send_cmd(int handle, PROTOCOL_CMD_STRUCT *protocol)
{
	size_t _rc = -1;
	if (handle && protocol)
	{
		uint32_t _send = (PROTO_CMD_START | protocol->cmd);
//		printf("send: %d\n", (int32_t)_send);


		_rc = write(handle, &_send, sizeof(_send));
		if (_rc <= 0)
			return -1;

//		printf("send1: %d\n", protocol->dataptr_size);
		if (protocol->dataptr_size)
		{
			_rc = write(handle, &protocol->dataptr_size, sizeof(protocol->dataptr_size));
			if (_rc <= 0)
				return -1;


			_rc = write(handle, protocol->dataptr, protocol->dataptr_size);
			if (_rc <= 0)
				return -1;
		}
		_rc = 1;

	}
	return _rc;
}

//-------------------------
#ifdef _MAIN_



#define EPG_EVENT_CONTENTMASK_UNDEFINED                0x00
#define EPG_EVENT_CONTENTMASK_MOVIEDRAMA               0x10
#define EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS       0x20
#define EPG_EVENT_CONTENTMASK_SHOW                     0x30
#define EPG_EVENT_CONTENTMASK_SPORTS                   0x40
#define EPG_EVENT_CONTENTMASK_CHILDRENYOUTH            0x50
#define EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE         0x60
#define EPG_EVENT_CONTENTMASK_ARTSCULTURE              0x70
#define EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS 0x80
#define EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE       0x90
#define EPG_EVENT_CONTENTMASK_LEISUREHOBBIES           0xA0
#define EPG_EVENT_CONTENTMASK_SPECIAL                  0xB0
#define EPG_EVENT_CONTENTMASK_USERDEFINED              0xF0

UTILS_HOSTPORT_STRUCT *hostport = NULL;



#define PROTO_MAIN_LIST_REC			1
#define PROTO_MAIN_LIST_CHAN		2
#define PROTO_MAIN_LIST_TIMER		3
#define PROTO_MAIN_SET_TIMER		4
#define PROTO_MAIN_DEL_REC			5
#define PROTO_MAIN_LIST_DEL			6
#define PROTO_MAIN_LIST_CHAN_COUNT	7
#define PROTO_MAIN_GET_EPG			8
#define PROTO_MAIN_STREAM_INFO		9

#define PROTO_MAIN_LIST_REC_COUNT	10
#define PROTO_MAIN_LIST_TIMER_COUNT	11
#define PROTO_MAIN_RELOAD_EPG		12


char *remote_ip = NULL;
char *dd_progid = NULL;
uint8_t proto_cmd = 0;
uint32_t prog_id = 0;

void display_usage(char *exe)
{
	fprintf(stderr,"bleah\n");
}

#define GENRE_MAIN_COUNT		22
#define GENRE_SUB_COUNT			43

static const char *GENRE_SUB[GENRE_SUB_COUNT] =
{
	"Baseball",
	"Basketball",
	"Golf",
	"Football",
	"Hockey",
	"Soccer",
	"Boxing",
	"Action and Adventure",
	"Science Fiction",
	"Horror",
	"Fantasy",
	"Drama",
	"Mystery",
	"Suspense",
	"Drama",
	"Musical",
	"Music",
	"Western",
	"Romance",
	"Awards/Event",
	"Business",
	"Cooking",
	"Home",
	"Interview",
	"Racing",
	"How-to",
	"Science",
	"Tennis",
	"Travel",
	"Weather",
	"Home and Garden",
	"Game",
	"Racing",
	"Outdoor",
	"Episodic",
	"Documentary",
	"Comedy",
	"Reality",
	"Religious",
	"Public Affairs",
	"Current Events",
	"Special",
	"Other",
};

static const char *GENRE_MAIN[GENRE_MAIN_COUNT] =
{
	"News",
	"Sports",
	"Paid Programming",
	"Movie",
	"Comedy",
	"Action/Adventure",
	"Talk Show",
	"Game Show",
	"Soap Opera",
	"Miniseries",
	"Drama",
	"Music",
	"Reality",
	"Lifestyle",
	"Children",
	"Cooking",
	"Adventure",
	"Special",
	"Educational",
	"Travel",
	"How-to",
	"Other",
};


static const char *optString = "a:c:i:d:?h";

static const struct option longOpts[] =
{
	{ "help", no_argument, NULL, 'h' },
	{ NULL, no_argument, NULL, 0 }
};

uint8_t get_opts(int argc, char *const argv[])
{
	int index = 0;
	int opt = getopt_long( argc, argv, optString, longOpts, &index );

	if (opt == -1 )
	{
		display_usage(argv[0]);
		return 1;
	}


	while ( opt != -1 )
	{
		switch ( opt )
		{
			case 'a':
				remote_ip = optarg;
				break;

			case 'd':
				dd_progid = optarg;
				break;

			case 'c':
				proto_cmd = atoi(optarg);
				break;

			case 'i':
				prog_id = atoi(optarg);
				break;

			case 'h':
			case '?':
				display_usage(argv[0]);
				break;

			default:
				break;
		}
		opt = getopt_long( argc, argv, optString, longOpts, &index );
	}
	return 0;
}

void sigint_handler()
{
	exit(0);
}

void sigpipe_handler()
{
//   printf("SIGPIPE caught\n");
}


int _proto_main_reload_epg(UTILS_HOSTPORT_STRUCT * hostp, char *id)
{
	if (hostp)
	{
		int sock = 0;

		protocol_epg_reload(hostp->hostname, hostp->port, &sock, id);
		if (sock > 0)
		{
			printf("Told Server to reload EPG with filename : %s\n", id);
			close(sock);
		}
	}
	return -1;
}

int _proto_main_get_epg(UTILS_HOSTPORT_STRUCT * hostp, TIMER_STRUCT_SEND *timer_send)
{
	if (hostp)
	{
		int sock = 0, err = 0, sz;
		protocol_get_channel_epg(hostp->hostname, hostp->port, &sock, timer_send);
		if (sock > 0)
		{
			int i, j;
			uint64_t count = 0;
			char *genre = NULL, *subgenre=NULL;
			TIMER_STRUCT timer = {{0}};;
			TIMER_STRUCT_EXTRA extra = {0};
			printf("HERE1\n");
//			sz = get_bytes_from_socket(sock, (uint8_t*)&count, sizeof(count), 5, 0, 0);
			sz = get_bytes_from_socket(sock, (uint8_t*)&count, sizeof(count), 0, &err);
			printf("1Count: %" PRId64"\n", count);
			if (sz == sizeof(count))
			{
				while(count && timer.data.is_last == 0)
				{
					sz = get_bytes_from_socket(sock, (uint8_t*)&timer.data, sizeof(TIMER_STRUCT_SEND), 0, &err);
					sz = get_bytes_from_socket(sock, (uint8_t*)&extra, sizeof(TIMER_STRUCT_EXTRA), 0, &err);
					printf("display-name: %s (num: %" PRId64")\n", timer.data.channel_name, timer.data.channel_num);
					printf("Title: %s\n", timer.data.title);
					printf("Url: %s\n", timer.data.url);
					printf("Plot-outline: %s\n", timer.data.plot_outline);
					printf("Plot: %s\n", timer.data.plot);
					printf("Start: %" PRId64", End: %" PRId64"\n", timer.data.start_epoch, timer.data.end_epoch);
					printf("icon: %s\n", extra.icon_path);
					printf("category count: %d\n", extra.category_count);
					for(j=0; j < GENRE_MAIN_COUNT; j++)
					{
						for(i=0; i < extra.category_count; i++)
						{
//							printf("H: %s -- %s\n", GENRE_MAIN[j], extra.category[i]);
							if (strcmp(extra.category[i],  GENRE_MAIN[j]) == 0)
							{
								genre = strdup(extra.category[i]);
								memset(extra.category[i], 0, sizeof(extra.category[i]));
								break;
							}
						}

						if (genre)
							break;
					}

					if (genre)
					{
						for(j=0; j < GENRE_SUB_COUNT; j++)
						{
							for(i=0; i < extra.category_count; i++)
							{
								if (extra.category[i][0] == 0)
									continue;

								if (strcmp(extra.category[i], GENRE_SUB[j]) == 0)
								{
									subgenre = strdup(extra.category[i]);
//									printf("MEEP: %s\n", subgenre);
//									extra.category[i][0] = '\0';
									break;
								}
//								else
//									printf("\t[%d] %s -- %s\n",j, extra.category[i], GENRE_SUB[j]);
							}

							if (subgenre)
								break;
						}

						if (!subgenre && strcmp(genre, "Paid Programming") != 0)
						{
							for(i=0; i < extra.category_count; i++)
							{
								if (strlen(extra.category[i]))
									printf("\t [%d] [%d] MOO: %s (%s)\n", extra.category_count, i, extra.category[i], genre);
							}
						}
//						printf("Found!: %s -- %s\n", genre, subgenre);
					}
					else
					{
						if (extra.category_count)
						{
							printf("No Main: %s -- cat count: %d, o_air: %li\n", timer.data.title, extra.category_count, extra.org_air_date);
							for(i=0; i < extra.category_count; i++)
								printf("\t%s\n", extra.category[i]);
						}
					}
					if (genre)
						free(genre);
					if (subgenre)
						free(subgenre);
					genre = subgenre = NULL;
//					printf("Found Main: %s\n", genre);
					printf("\n");
				}
			}

			close(sock);
		}
	}
	return -1;
}
int _proto_main_get_timer_list(UTILS_HOSTPORT_STRUCT * hostp)
{
	if (hostp)
	{
		int sock = 0, sz, err = 0;
		protocol_get_timer_list(hostp->hostname, hostp->port, &sock);
		if (sock > 0)
		{
			TIMER_STRUCT timer = {{0}};
			uint32_t count = 0;
//			sz = get_bytes_from_socket(sock, (uint8_t*)&count, sizeof(count), 5, 0, 0);
			sz = get_bytes_from_socket(sock, (uint8_t*)&count, sizeof(count), 2000, &err);
			printf("2count: %d\n", count);
			if (sz == sizeof(count))
			{
				while(count && timer.data.is_last == 0)
				{
//					sz = get_bytes_from_socket(sock, (uint8_t*)&timer, sizeof(TIMER_STRUCT), 5, 0, 0);
//					sz = get_bytes_from_socket(sock, (uint8_t*)&timer, sizeof(TIMER_STRUCT), 2000, &err);
					sz = get_bytes_from_socket(sock, (uint8_t*)&timer.data, sizeof(TIMER_STRUCT_SEND), 2000, &err);
					timer_print_timer2(&timer);
				}
			}
			close(sock);
			return 0;
		}
	}
	return -1;
}

int _proto_main_del_rec(UTILS_HOSTPORT_STRUCT * hostp, uint32_t id)
{
	if (hostp)
	{
		int sock = 0, sz, err = 0;
		printf("Removing recording num: %d\n", id);
		protocol_del_rec_id2(hostp->hostname, hostp->port, id, &sock);
		if (sock > 0)
		{
			int ret = 0;
			uint8_t rc = 0;
			printf("del_rc, sock good\n");
//			sz = get_bytes_from_socket(sock, (uint8_t*)&rc, sizeof(rc), 5, 0, 0);
			sz = get_bytes_from_socket(sock, (uint8_t*)&rc, sizeof(rc), 2000, &err);

			if (sz == sizeof(rc) && rc == PROTOCOL_INIT_GOOD)
			{
				printf("Deleted ID: %d\n", id);
				ret = 0;
			}
			else
			{
				printf("NOT Deleted ID: %d (%d)\n", id, rc);
				ret = -1;
			}

			close(sock);
			return ret;
		}
		else
			printf("del_rc, sock bad\n");

	}
	return -1;
}

int _proto_main_del_list(UTILS_HOSTPORT_STRUCT * hostp, uint32_t id)
{
	if (hostp)
	{
		int sock = 0, sz, err = 0;
		printf("Removing list num: %d\n", id);
		protocol_del_timer2(hostp->hostname, hostp->port, id, &sock);
		if (sock > 0)
		{
			int ret = 0;
			uint8_t rc = 0;
			printf("del_rc, sock good\n");
//			sz = get_bytes_from_socket(sock, (uint8_t*)&rc, sizeof(rc), 5, 0, 0);
			sz = get_bytes_from_socket(sock, (uint8_t*)&rc, sizeof(rc), 2000, &err);
			if (sz == sizeof(rc) && rc == PROTOCOL_INIT_GOOD)
			{
				printf("Deleted Timer ID: %d\n", id);
				ret = 0;
			}
			else
			{
				printf("NOT Deleted Timer ID: %d (%d)\n", id, rc);
				ret = -1;
			}
			close(sock);
			return ret;
		}
		else
			printf("del_rc, sock bad\n");

	}
	return -1;
}

int _proto_main_get_rec_list(UTILS_HOSTPORT_STRUCT * hostp)
{
	if (hostp)
	{
		int sock = 0, sz, err = 0;
		protocol_get_rec_list(hostp->hostname, hostp->port, &sock);
		if (sock > 0)
		{
			TIMER_STRUCT timer = {{0}};
			uint32_t count = 0, _count = 0;
			sz = get_bytes_from_socket(sock, (uint8_t*)&count, sizeof(count), 2000, &err);
//			printf("count: %d\n", count);
//			while(count && timer.is_last == 0)
			if (sz == sizeof(count))
			{
				while(_count < count)
				{
//					sz = get_bytes_from_socket(sock, (uint8_t*)&timer, sizeof(TIMER_STRUCT), 5, 0, 0);
					sz = get_bytes_from_socket(sock, (uint8_t*)&timer, sizeof(TIMER_STRUCT), 2000, &err);
					printf("[%" PRId64"],[%d],[%li],[%li],[%s],[%s],[%s],[%s],[%s],[%s]\n", timer.data.channel_num, timer.data.id, timer.data.start_epoch, timer.data.end_epoch, timer.data.channel_name, timer.data.title, timer.data.plot_outline, timer.data.plot, timer.data.genre, timer.data.sub_genre);
//					timer_print_timer(&timer);
					_count++;
				}
			}
			close(sock);
			return 0;
		}
	}
	return -1;
}


int _proto_main_get_chan_count(UTILS_HOSTPORT_STRUCT * hostp)
{
	if (hostp)
	{
		int sock = 0, sz, count = 0, err;
		protocol_get_channel_count(hostp->hostname, hostp->port, &sock);
		if (sock > 0)
		{
//			sz = get_bytes_from_socket(sock, (uint8_t*)&count, sizeof(count), 5, 0, 0);
			sz = get_bytes_from_socket(sock, (uint8_t*)&count, sizeof(count), 2000, &err);
			if (sz != sizeof(count))
				count = -1;
			close(sock);
		}
		sock = 0;
		printf("Count %d\n", count);

		int i;
		for(i=1; i <= count; i++)
		{
			char tmp[255] = {0};
			uint64_t f_time = (uint64_t)time(NULL);
//			sprintf(tmp, "%03d_%" PRId64"_5", i + 3000, f_time);
			sprintf(tmp, "%04d_%" PRId64"", i + 3000, f_time);
			printf("Get EPG: %s\n", tmp);
//			_proto_main_get_epg(hostp, tmp);
		}

		return count;
	}
	return -1;
}

int _proto_main_get_rec_count(UTILS_HOSTPORT_STRUCT * hostp)
{
	if (hostp)
	{
		int sock = 0, err = 0, sz,  count=0;
		protocol_get_rec_count(hostp->hostname, hostp->port, &sock);
		if (sock > 0)
		{
			sz = get_bytes_from_socket(sock, (uint8_t*)&count, sizeof(count), 2000, &err);
			if (sz != sizeof(count))
				count = -1;
			close(sock);
		}
		sock = 0;
		printf("Rec Count %d\n", count);
		return count;
	}
	return -1;
}

int _proto_main_get_timer_count(UTILS_HOSTPORT_STRUCT * hostp)
{
	if (hostp)
	{
		int sock = 0, err = 0, sz, count=0;
		protocol_get_timer_count(hostp->hostname, hostp->port, &sock);
		if (sock > 0)
		{
			sz = get_bytes_from_socket(sock, (uint8_t*)&count, sizeof(count), 2000, &err);
			if (sz != sizeof(count))
				count = -1;
			close(sock);
		}
		sock = 0;
		printf("Timer Count %d\n", count);
		return count;
	}
	return -1;
}

int _proto_main_get_chan_list(UTILS_HOSTPORT_STRUCT * hostp)
{
	if (hostp)
	{
		int sock = 0, err = 0, sz, f = 0;
		protocol_get_channel_list(hostp->hostname, hostp->port, &sock);
		if (sock > 0)
		{
			PROTOCOL_CHANNEL_STRUCT p_channel;
			memset(&p_channel, 0, sizeof(PROTOCOL_CHANNEL_STRUCT));
			while(p_channel.is_last == 0)
			{
				sz = get_bytes_from_socket(sock, (uint8_t*)&p_channel, sizeof(PROTOCOL_CHANNEL_STRUCT), 2000, &err);
				if (sz == sizeof(PROTOCOL_CHANNEL_STRUCT))
				{
					printf("[%d] Channel %d, Name: %s, xmltv_id: %s, i_url: %s (%d)\n", f, p_channel.num, p_channel.name, p_channel.xmltv_id, p_channel.icon_path,  p_channel.is_last);
					f++;
				}
				else
					break;
			}
			close(sock);
			return 0;
		}
	}
	return -1;
}

int _proto_main_get_stream_info(UTILS_HOSTPORT_STRUCT * hostp)
{
	if (hostp)
	{
		int sock = 0;
		protocol_get_stream_info(hostp->hostname, hostp->port, &sock);
		if (sock > 0)
		{
/*
			PROTOCOL_STREAM_STRUCT stream = {0};
			while(stream.is_last == 0)
			{
				sz = get_bytes_from_socket(sock, (uint8_t*)&stream, sizeof(stream), 5, 0, 0);
				printf("Stream info, pid: %d -- type: %d (%d)\n", stream.pid, stream.type, stream.is_last);
				f++;
			}
*/
/*
			PROTOCOL_CHANNEL_STRUCT p_channel= {0};
			while(p_channel.is_last == 0)
			{
				sz = get_bytes_from_socket(sock, (uint8_t*)&p_channel, sizeof(PROTOCOL_CHANNEL_STRUCT), 5, 0, 0);
				printf("[%d] Channel %d, Name: %s (%d)\n", f, p_channel.num, p_channel.name, p_channel.is_last);
				f++;
			}
*/
			close(sock);
			return 0;
		}
	}
	return -1;
}

int _proto_main_set_timer(UTILS_HOSTPORT_STRUCT * hostp, uint64_t chan, char *progid)
{
	if (hostp)
	{
		int sock;
		TIMER_STRUCT timer = {{0}};

		if (progid)
		{
			timer.data.id = TIMER_USE_DD_PROGID;
			strncpy(timer.data.title, progid, sizeof(timer.data.title) - 1);
//			printf("Sending prod_id: %s\n", timer.data.title);
			//return 0;
		}
		else
		{
			timer.data.id = 5;
			timer.data.status = 4;
			timer.data.channel_num = chan;
			strncpy(timer.data.channel_name,"ED1", sizeof(timer.data.channel_name) - 1);
			strncpy(timer.data.title,"Fake Title", sizeof(timer.data.title) - 1);
			strncpy(timer.data.plot,"Faake Plot", sizeof(timer.data.plot) - 1);
			strncpy(timer.data.plot_outline,"Plot Lines", sizeof(timer.data.plot_outline) - 1);
			strncpy(timer.data.genre,"Fake Genere1", sizeof(timer.data.genre) - 1);
			strncpy(timer.data.sub_genre,"Fake SebGenere1", sizeof(timer.data.sub_genre) - 1);

			timer.data.start_epoch = ((int64_t)time(NULL)) + 2;
			timer.data.end_epoch = timer.data.start_epoch + 30;
		}
		printf("Start Time: %li, End Time: %li\n", timer.data.start_epoch, timer.data.end_epoch);
		protocol_add_timer(hostp->hostname, hostp->port, (void*)&timer, sizeof(TIMER_STRUCT), &sock);

		return 0;
	}
	return -1;
}

int main(int argc, char *argv[])
{
	signal(SIGPIPE,sigpipe_handler);
	signal(SIGINT,sigint_handler);

    get_opts(argc, argv);
	if (remote_ip && proto_cmd > 0)
	{
		hostport = utils_split_host(remote_ip);
//		printf("cmd: %d, ip: %s, port: %d\n", proto_cmd, hostport->hostname, hostport->port);

		switch(proto_cmd)
		{
			case PROTO_MAIN_LIST_REC :
//				printf("Getting Recordings List\n");
				_proto_main_get_rec_list(hostport);
			break;

			case PROTO_MAIN_LIST_DEL :
				
				_proto_main_del_list(hostport, prog_id);
			break;

			case PROTO_MAIN_DEL_REC :
				_proto_main_del_rec(hostport, prog_id);
			break;

			case PROTO_MAIN_LIST_CHAN :
//				printf("Getting Channel List\n");
				_proto_main_get_chan_list(hostport);
			break;

			case PROTO_MAIN_LIST_TIMER :
//				printf("Getting Timer List\n");
				_proto_main_get_timer_list(hostport);
			break;

			case PROTO_MAIN_SET_TIMER :
//				printf("Setting Timer\n");
				_proto_main_set_timer(hostport, 802, dd_progid);
			break;

			case PROTO_MAIN_LIST_CHAN_COUNT :
//				printf("Setting Timer\n");
				_proto_main_get_chan_count(hostport);
			break;

			case PROTO_MAIN_LIST_REC_COUNT :
//				printf("Setting Timer\n");
				_proto_main_get_rec_count(hostport);
			break;

			case PROTO_MAIN_LIST_TIMER_COUNT :
//				printf("Setting Timer\n");
				_proto_main_get_timer_count(hostport);
			break;

			case PROTO_MAIN_STREAM_INFO :

//				printf("Setting Timer\n");
				_proto_main_get_stream_info(hostport);
			break;

			case PROTO_MAIN_RELOAD_EPG :
				printf("Reload EPG\n");
				_proto_main_reload_epg(hostport, NULL);
				
			break;

			case PROTO_MAIN_GET_EPG :
			{
				TIMER_STRUCT_SEND timer = {0};
//				strncpy(timer.url, "104", sizeof(timer.url) - 1);
				if (prog_id == 0)
					prog_id = 104;
				snprintf(timer.url, sizeof(timer.url) -1, "%d", prog_id);
				timer.start_epoch = time(NULL);
				timer.end_epoch = timer.start_epoch + (7*86400);

				_proto_main_get_epg(hostport, &timer);
/*
//				if (prog_id)
				{
					uint64_t f_time = 1374657309;
					char tmp[255] = {0};
					f_time = (uint64_t)time(NULL);
					sprintf(tmp, "%04d_%" PRId64"", 104, f_time);
					printf("Get EPG: %s\n", tmp);
					_proto_main_get_epg(hostport, tmp);
				}
*/
			}
			break;
		}
	}
//	_doconnect(argv[1], atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5]) );
//	usleep(1000 *1000 * 10);
//	get_opts(argc, argv);
//	printf("BYE!\n");
	return 0;
}
#endif

